﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace Ongoal.Quotation.Service.Common
{
 /// <summary>
        /// 利用表达式目录树进行实体映射
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TTarget"></typeparam>
        public static class ExpressionMapper<TSource, TTarget>
            where TSource : class, new()
            where TTarget : class, new()
        {
            private static Func<TSource, TTarget> _func = null;

            static ExpressionMapper()
            {
                try
                {
                    ParameterExpression parameterExpression = Expression.Parameter(typeof(TSource), "s");
                    List<MemberBinding> memberBindings = new List<MemberBinding>();
                foreach (var item in typeof(TTarget).GetProperties())
                    {
                    var name = item.Name;
                    //特性集合
                    var attrbutes = item.GetCustomAttributes(true);
                        foreach (var attr in attrbutes)
                         {
                        if (attr is modelattrbute)
                        {
                            modelattrbute attrbute = (modelattrbute)attr;
                            //使用特性名称
                            name = attrbute.name;
                        }
                       }
                        
                        var sProp = typeof(TSource).GetProperty(name);
                        if (sProp != null && sProp.PropertyType == item.PropertyType && sProp.CanWrite && item.CanWrite)
                        {
                            MemberExpression property = Expression.Property(parameterExpression, sProp);
                            MemberBinding memberBinding = Expression.Bind(item, property);
                            memberBindings.Add(memberBinding);
                        }
                    }
                    foreach (var item in typeof(TTarget).GetFields())
                    {

                    var name = item.Name;
                    //特性集合
                    var attrbutes = item.GetCustomAttributes(true);
                    foreach (var attr in attrbutes)
                    {
                        if (attr is modelattrbute)
                        {
                            modelattrbute attrbute = (modelattrbute)attr;
                            //使用特性名称
                            name = attrbute.name;
                        }
                    }
                    var sField = typeof(TSource).GetField(name);
                        if (sField != null && sField.FieldType == item.FieldType)
                        {
                            MemberExpression property = Expression.Field(parameterExpression, sField);
                            MemberBinding memberBinding = Expression.Bind(item, property);
                            memberBindings.Add(memberBinding);
                        }
                    }
                    MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TTarget)), memberBindings);

                    Expression<Func<TSource, TTarget>> lamada = Expression.Lambda<Func<TSource, TTarget>>(memberInitExpression, new ParameterExpression[] {
            parameterExpression
            });
                    _func = lamada.Compile();
                }
                catch (Exception ex)
                {
                throw new Exception(ex.Message);
                }
            }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
            public static TTarget Map(TSource source)
            {
                return _func.Invoke(source);
            }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>

            public static List<TTarget> Map(List<TSource> source)
            {
                var ret = new List<TTarget>();
                foreach (var item in source)
                {
                    ret.Add(_func.Invoke(item));
                }
                return ret;
            }
        }
   
}
